﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Extensibility;
using PostSharp.Reflection;

namespace BSF.Attributes
{
    /// <summary>
    /// 跟踪Model的属性变化，以便EF中在Update到数据库时不会全部字段都更新
    /// </summary>
    //[MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
    [Serializable]
    [IntroduceInterface(typeof(ITrackable), OverrideAction = InterfaceOverrideAction.Ignore)]
    public class TrackingAttribute : InstanceLevelAspect, ITrackable//, IAspectProvider
    {
        [OnLocationSetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property)]
        public void OnSetValue(LocationInterceptionArgs args)
        {
            //Console.WriteLine("Set value for " + args.LocationName);
            if (IsTracking && args.LocationName != "IsTracking" && args.LocationName != "ChangedProperties")
            {
                //只有新旧value不同，才记录该属性发生改变
                if (args.Value != args.GetCurrentValue())
                {
                    ModifiedProperties[args.LocationName] = true;
                }
            }

            args.ProceedSetValue();
        }

        /// <summary>
        /// 记录哪些属性值发生改变
        /// </summary>
        [IntroduceMember(OverrideAction = MemberOverrideAction.OverrideOrFail, Visibility = Visibility.Private)]
        public IDictionary<string, bool> ModifiedProperties { get; set; }

        /// <summary>
        /// 是否开启跟踪状态,默认值为开启跟踪
        /// </summary>
        [IntroduceMember(OverrideAction = MemberOverrideAction.OverrideOrFail, Visibility = Visibility.Private)]
        public bool IsTracking { get; set; }

        [OnMethodExitAdvice, MulticastPointcut(MemberName = ".ctor")]
        public void OnExit(MethodExecutionArgs args)
        {
            IsTracking = true;
            ModifiedProperties = new Dictionary<string, bool>();
        }


        ///// <summary>
        ///// 注入JsonIgnoreAttribute
        ///// </summary>
        ///// <param name="targetElement"></param>
        ///// <returns></returns>
        //public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        //{
        //    Type targetType = (Type)targetElement;


        //    CustomAttributeIntroductionAspect introduceDataMemberAspect =
        //        new CustomAttributeIntroductionAspect(
        //            new ObjectConstruction(typeof(JsonIgnoreAttribute).GetConstructor(Type.EmptyTypes)));



        //    // Add a DataMember attribute to every relevant property. 
        //    foreach (PropertyInfo property in
        //        targetType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
        //    {
        //        if (property.Name == "IsTracking" || property.Name == "ChangedProperties")
        //            yield return new AspectInstance(property, introduceDataMemberAspect);
        //    }   
        //}
    }

}
